﻿// ....................................................................................................................
//	Author: Copyright (C) 2012 Ing. Marek Hubal
//	Email: hubal@acasoftware.org
// ....................................................................................................................

using System;

namespace core
{
    /// <summary>Trieda IExportCDTracks_Str</summary>
    public class IExportCDTracks_Str
    {
        public const int OUTPUT_TYPE_AUDIO_WAV = 0;
        public const int OUTPUT_TYPE_AUDIO_MP3 = 2;
        public const int OUTPUT_TYPE_DATA_ISO = 1;

        public string OutputPath; // Vystupna cesta
        public int OutputTypeAudio; // Typ vystupneho suboru pre audio
        public int OutputTypeData; // Typ vystupneho suboru pre data
        
        public uint MP3_BitRate; // MP3 nastavenia
        public bool MP3_Copyright;
        public bool MP3_CRC;
        public bool MP3_Original;
        public bool MP3_Private;
        public bool MP3_UseVBR;
        public uint MP3_VBRMaxBitRate;
        public uint MP3_VBRAverageBitRate;
        public uint MP3_VBRQuality;
        public uint MP3_Quality;

        /// <summary>Konstruktor</summary>
        public IExportCDTracks_Str()
        {
            OutputPath = IFileSystem.GetSpecialPath(IFileSystem.SPECIAL_PATH_ID_MY_MUSIC);
            OutputTypeAudio = OUTPUT_TYPE_AUDIO_MP3;
            OutputTypeData = OUTPUT_TYPE_DATA_ISO;
            MP3_BitRate = 128;
            MP3_Copyright = false;
            MP3_CRC = false;
            MP3_Original = true;
            MP3_Private = false;
            MP3_UseVBR = false;
            MP3_VBRMaxBitRate = 128;
            MP3_VBRAverageBitRate = 128;
            MP3_VBRQuality = 9;
            MP3_Quality = 0;

        }

        /// <summary>Serializacia obsahu</summary>
        /// <returns>serializovany obsah</returns>
        public string Serialize()
        {
            using (IParamList L = new IParamList())
            {
                L.SetParam("OP", OutputPath);
                L.SetParam("OTA", OutputTypeAudio);
                L.SetParam("OTD", OutputTypeData);
                L.SetParam("MP3_BR", MP3_BitRate);
                L.SetParam("MP3_CO", MP3_Copyright);
                L.SetParam("MP3_CRC", MP3_CRC);
                L.SetParam("MP3_O", MP3_Original);
                L.SetParam("MP3_P", MP3_Private);
                L.SetParam("MP3_U", MP3_UseVBR);
                L.SetParam("MP3_VBRM", MP3_VBRMaxBitRate);
                L.SetParam("MP3_VBRA", MP3_VBRAverageBitRate);
                L.SetParam("MP3_VBRQ", MP3_VBRQuality);
                L.SetParam("MP3_Q", MP3_Quality);

                return L.Serialize(true); // Serializujem
            }
        }
        /// <summary>Deserializacia obsahu</summary>
        /// <param name="pData">serializovany obsah</param>
        public void Deserialize(string pData)
        {
            using (IParamList L = new IParamList())
            {
                L.Deserialize(pData, true);
                OutputPath = L.GetParam("OP", OutputPath);
                OutputTypeAudio = L.GetParam("OTA", OutputTypeAudio);
                OutputTypeData = L.GetParam("OTD", OutputTypeData);
                MP3_BitRate = L.GetParam("MP3_BR", MP3_BitRate);
                MP3_Copyright = L.GetParam("MP3_CO", MP3_Copyright);
                MP3_CRC = L.GetParam("MP3_CRC", MP3_CRC);
                MP3_Original = L.GetParam("MP3_O", MP3_Original);
                MP3_Private = L.GetParam("MP3_P", MP3_Private);
                MP3_UseVBR = L.GetParam("MP3_U", MP3_UseVBR);
                MP3_VBRMaxBitRate = L.GetParam("MP3_VBRM", MP3_VBRMaxBitRate);
                MP3_VBRAverageBitRate = L.GetParam("MP3_VBRA", MP3_VBRAverageBitRate);
                MP3_VBRQuality = L.GetParam("MP3_VBRQ", MP3_VBRQuality);
                MP3_Quality = L.GetParam("MP3_Q", MP3_Quality);
            }
        }

        /// <summary>Ziskanie pripony suboru podla zadaneho typu</summary>
        /// <param name="pType">typ</param>
        /// <returns>pripona</returns>
        public static string GetExtension(int pType)
        {
            switch (pType)
            {
                case OUTPUT_TYPE_AUDIO_WAV: return "wav";
                case OUTPUT_TYPE_DATA_ISO: return "iso";
                case OUTPUT_TYPE_AUDIO_MP3: return "mp3";
                default: return "";
            }
        }
    }

    /// <summary>Trieda IWAVWriterStream</summary>
    public class IWAVWriterStream : System.IO.FileStream 
    {
        /// <summary>Konstruktor</summary>
        /// <param name="path">cesta</param>
        /// <param name="mode">mod</param>
        /// <param name="access">pristup</param>
        /// <param name="share">zdielanie</param>
        public IWAVWriterStream(string path, uint pSamplingRate, ushort pBitsPerSample, ushort pChannels, uint pDataSize)
            : base(path, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.Delete)
        {
            WriteByte((byte)'R');
            WriteByte((byte)'I');
            WriteByte((byte)'F');
            WriteByte((byte)'F');
            byte[] B = BitConverter.GetBytes((uint)(pDataSize + 44)); Write(B, 0, B.Length);
            WriteByte((byte)'W');
            WriteByte((byte)'A');
            WriteByte((byte)'V');
            WriteByte((byte)'E');
            WriteByte((byte)'f');
            WriteByte((byte)'m');
            WriteByte((byte)'t');
            WriteByte((byte)' ');
            B = BitConverter.GetBytes((uint)(16)); Write(B, 0, B.Length);
            B = BitConverter.GetBytes((ushort)(1)); Write(B, 0, B.Length);
            B = BitConverter.GetBytes((ushort)(pChannels)); Write(B, 0, B.Length);
            B = BitConverter.GetBytes((uint)(pSamplingRate)); Write(B, 0, B.Length);
            B = BitConverter.GetBytes((uint)(pChannels * pBitsPerSample * pSamplingRate / 8)); Write(B, 0, B.Length);
            B = BitConverter.GetBytes((ushort)(pChannels * pBitsPerSample / 8)); Write(B, 0, B.Length);
            B = BitConverter.GetBytes((ushort)(pBitsPerSample)); Write(B, 0, B.Length);
            WriteByte((byte)'d');
            WriteByte((byte)'a');
            WriteByte((byte)'t');
            WriteByte((byte)'a');
            B = BitConverter.GetBytes((uint)(pDataSize)); Write(B, 0, B.Length);
        }
    }

    /// <summary>Trieda IMP3WriterStream</summary>
    public class IMP3WriterStream : System.IO.FileStream
    {
        #region Enums
        public enum VBRMETHOD : int
        {
            VBR_METHOD_NONE = -1,
            VBR_METHOD_DEFAULT = 0,
            VBR_METHOD_OLD = 1,
            VBR_METHOD_NEW = 2,
            VBR_METHOD_MTRH = 3,
            VBR_METHOD_ABR = 4
        }
        public enum MpegMode : uint
        {
            STEREO = 0,
            JOINT_STEREO,
            DUAL_CHANNEL,
            MONO,
            NOT_SET,
            MAX_INDICATOR
        }
        public enum LAME_QUALITY_PRESET : int
        {
            LQP_NOPRESET = -1,
            // QUALITY PRESETS
            LQP_NORMAL_QUALITY = 0,
            LQP_LOW_QUALITY = 1,
            LQP_HIGH_QUALITY = 2,
            LQP_VOICE_QUALITY = 3,
            LQP_R3MIX = 4,
            LQP_VERYHIGH_QUALITY = 5,
            LQP_STANDARD = 6,
            LQP_FAST_STANDARD = 7,
            LQP_EXTREME = 8,
            LQP_FAST_EXTREME = 9,
            LQP_INSANE = 10,
            LQP_ABR = 11,
            LQP_CBR = 12,
            LQP_MEDIUM = 13,
            LQP_FAST_MEDIUM = 14,
            // NEW PRESET VALUES
            LQP_PHONE = 1000,
            LQP_SW = 2000,
            LQP_AM = 3000,
            LQP_FM = 4000,
            LQP_VOICE = 5000,
            LQP_RADIO = 6000,
            LQP_TAPE = 7000,
            LQP_HIFI = 8000,
            LQP_CD = 9000,
            LQP_STUDIO = 10000
        }
        public enum WaveFormats
        {
            Pcm = 1,
		    Float = 3
	    }
        #endregion
        #region Struktury
        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] 
        public class WaveFormat
        {
            public short wFormatTag;
            public short nChannels;
            public int nSamplesPerSec;
            public int nAvgBytesPerSec;
            public short nBlockAlign;
            public short wBitsPerSample;
            public short cbSize;

            public WaveFormat(int rate, int bits, int channels)
            {
                wFormatTag = (short)WaveFormats.Pcm;
                nChannels = (short)channels;
                nSamplesPerSec = rate;
                wBitsPerSample = (short)bits;
                cbSize = 0;
               
                nBlockAlign = (short)(channels * (bits / 8));
                nAvgBytesPerSec = nSamplesPerSec * nBlockAlign;
            }
        }
        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential), Serializable]
        public struct MP3 //BE_CONFIG_MP3
        {
            public uint dwSampleRate;
            public byte byMode;
            public ushort wBitrate;
            public int bPrivate;
            public int bCRC;
            public int bCopyright;
            public int bOriginal;
        }
        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Size = 327), Serializable]
        public struct LHV1 // BE_CONFIG_LAME LAME header version 1
        {
            public const uint MPEG1 = 1;
            public const uint MPEG2 = 0;

            // STRUCTURE INFORMATION
            public uint dwStructVersion;
            public uint dwStructSize;
            // BASIC ENCODER SETTINGS
            public uint dwSampleRate;		// SAMPLERATE OF INPUT FILE
            public uint dwReSampleRate;		// DOWNSAMPLERATE, 0=ENCODER DECIDES  
            public MpegMode nMode;				// STEREO, MONO
            public uint dwBitrate;			// CBR bitrate, VBR min bitrate
            public uint dwMaxBitrate;		// CBR ignored, VBR Max bitrate
            public LAME_QUALITY_PRESET nPreset;			// Quality preset
            public uint dwMpegVersion;		// MPEG-1 OR MPEG-2
            public uint dwPsyModel;			// FUTURE USE, SET TO 0
            public uint dwEmphasis;			// FUTURE USE, SET TO 0
            // BIT STREAM SETTINGS
            public int bPrivate;			// Set Private Bit (TRUE/FALSE)
            public int bCRC;				// Insert CRC (TRUE/FALSE)
            public int bCopyright;			// Set Copyright Bit (TRUE/FALSE)
            public int bOriginal;			// Set Original Bit (TRUE/FALSE)
            // VBR STUFF
            public int bWriteVBRHeader;	// WRITE XING VBR HEADER (TRUE/FALSE)
            public int bEnableVBR;			// USE VBR ENCODING (TRUE/FALSE)
            public int nVBRQuality;		// VBR QUALITY 0..9
            public uint dwVbrAbr_bps;		// Use ABR in stead of nVBRQuality
            public VBRMETHOD nVbrMethod;
            public int bNoRes;				// Disable Bit resorvoir (TRUE/FALSE)
            // MISC SETTINGS
            public int bStrictIso;			// Use strict ISO encoding rules (TRUE/FALSE)
            public ushort nQuality;			// Quality Setting, HIGH BYTE should be NOT LOW byte, otherwhise quality=5

            public LHV1(WaveFormat format, uint MpeBitRate)
            {
                dwStructVersion = 1;
                dwStructSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(BE_CONFIG));
                switch (format.nSamplesPerSec)
                {
                    case 16000:
                    case 22050:
                    case 24000:
                        dwMpegVersion = MPEG2;
                        break;
                    default:
                        dwMpegVersion = MPEG1;
                        break;
                }
                dwSampleRate = (uint)format.nSamplesPerSec;
                dwReSampleRate = 0;
                switch (format.nChannels)
                {
                    case 1:
                        nMode = MpegMode.MONO;
                        break;
                    default:
                        nMode = MpegMode.STEREO;
                        break;
                }
                switch (MpeBitRate)
                {
                    case 32:
                    case 40:
                    case 48:
                    case 56:
                    case 64:
                    case 80:
                    case 96:
                    case 112:
                    case 128:
                    case 160: //Allowed bit rates in MPEG1 and MPEG2
                        break;
                    case 192:
                    case 224:
                    case 256:
                    case 320: //Allowed only in MPEG1
                        if (dwMpegVersion != MPEG1)
                        {
                            throw new ArgumentOutOfRangeException();
                        }
                        break;
                    case 8:
                    case 16:
                    case 24:
                    case 144: //Allowed only in MPEG2
                        if (dwMpegVersion != MPEG2)
                        {
                            throw new ArgumentOutOfRangeException();
                        }
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }

                dwBitrate = MpeBitRate;					// MINIMUM BIT RATE
                nPreset = LAME_QUALITY_PRESET.LQP_NORMAL_QUALITY;		// QUALITY PRESET SETTING
                dwPsyModel = 0;					// USE DEFAULT PSYCHOACOUSTIC MODEL 
                dwEmphasis = 0;					// NO EMPHASIS TURNED ON
                bOriginal = 1;					// SET ORIGINAL FLAG
                bWriteVBRHeader = 0;
                bNoRes = 0;					// No Bit resorvoir
                bCopyright = 0;
                bCRC = 0;
                bEnableVBR = 0;
                bPrivate = 0;
                bStrictIso = 0;
                dwMaxBitrate = 0;
                dwVbrAbr_bps = 0;
                nQuality = 0;
                nVbrMethod = VBRMETHOD.VBR_METHOD_NONE;
                nVBRQuality = 0;
            }
        }
        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential), Serializable]
        public struct ACC
        {
            public uint dwSampleRate;
            public byte byMode;
            public ushort wBitrate;
            public byte byEncodingMethod;
        }
        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit), Serializable]
        public class Format
        {
            [System.Runtime.InteropServices.FieldOffset(0)]
            public MP3 mp3;
            [System.Runtime.InteropServices.FieldOffset(0)]
            public LHV1 lhv1;
            [System.Runtime.InteropServices.FieldOffset(0)]
            public ACC acc;
            public Format(WaveFormat format, uint MpeBitRate)
            {
                lhv1 = new LHV1(format, MpeBitRate);
            }
        }
        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential), Serializable]
        public class BE_CONFIG
        {
            // encoding formats
            public const uint BE_CONFIG_MP3 = 0;
            public const uint BE_CONFIG_LAME = 256;

            public uint dwConfig;
            public Format format;

            public BE_CONFIG(WaveFormat format, uint MpeBitRate)
            {
                this.dwConfig = BE_CONFIG_LAME;
                this.format = new Format(format, MpeBitRate);
            }
            public BE_CONFIG(WaveFormat format)
                : this(format, 128)
            {
            }
        }
        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
        public class BE_VERSION
        {
            public const uint BE_MAX_HOMEPAGE = 256;
            public byte byDLLMajorVersion;
            public byte byDLLMinorVersion;
            public byte byMajorVersion;
            public byte byMinorVersion;
            // DLL Release date
            public byte byDay;
            public byte byMonth;
            public ushort wYear;
            //Homepage URL
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 257/*BE_MAX_HOMEPAGE+1*/)]
            public string zHomepage;
            public byte byAlphaLevel;
            public byte byBetaLevel;
            public byte byMMXEnabled;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 125)]
            public byte[] btReserved;
            public BE_VERSION()
            {
                btReserved = new byte[125];
            }
        }
        #endregion
        #region Importovane funkcie
        [System.Runtime.InteropServices.DllImport("Lame_enc.dll")]
        public static extern uint beInitStream(BE_CONFIG pbeConfig, ref uint dwSamples, ref uint dwBufferSize, ref uint phbeStream);
        [System.Runtime.InteropServices.DllImport("Lame_enc.dll")]
        public static extern uint beEncodeChunk(uint hbeStream, uint nSamples, short[] pInSamples, [System.Runtime.InteropServices.In, System.Runtime.InteropServices.Out] byte[] pOutput, ref uint pdwOutput);
        [System.Runtime.InteropServices.DllImport("Lame_enc.dll")]
        protected static extern uint beEncodeChunk(uint hbeStream, uint nSamples, IntPtr pSamples, [System.Runtime.InteropServices.In, System.Runtime.InteropServices.Out] byte[] pOutput, ref uint pdwOutput);
        [System.Runtime.InteropServices.DllImport("Lame_enc.dll")]
        public static extern uint beDeinitStream(uint hbeStream, [System.Runtime.InteropServices.In, System.Runtime.InteropServices.Out] byte[] pOutput, ref uint pdwOutput);
        [System.Runtime.InteropServices.DllImport("Lame_enc.dll")]
        public static extern uint beCloseStream(uint hbeStream);
        [System.Runtime.InteropServices.DllImport("Lame_enc.dll")]
        public static extern void beVersion([System.Runtime.InteropServices.Out] BE_VERSION pbeVersion);
        [System.Runtime.InteropServices.DllImport("Lame_enc.dll", CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
        public static extern void beWriteVBRHeader(string pszMP3FileName);
        [System.Runtime.InteropServices.DllImport("Lame_enc.dll")]
        public static extern uint beEncodeChunkFloatS16NI(uint hbeStream, uint nSamples, [System.Runtime.InteropServices.In]float[] buffer_l, [System.Runtime.InteropServices.In]float[] buffer_r, [System.Runtime.InteropServices.In, System.Runtime.InteropServices.Out]byte[] pOutput, ref uint pdwOutput);
        [System.Runtime.InteropServices.DllImport("Lame_enc.dll")]
        public static extern uint beFlushNoGap(uint hbeStream, [System.Runtime.InteropServices.In, System.Runtime.InteropServices.Out]byte[] pOutput, ref uint pdwOutput);
        [System.Runtime.InteropServices.DllImport("Lame_enc.dll", CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
        public static extern uint beWriteInfoTag(uint hbeStream, string lpszFileName);
        #endregion

        /// <summary>Zakodovanie bloku</summary>
        /// <param name="hbeStream"></param>
        /// <param name="buffer"></param>
        /// <param name="index"></param>
        /// <param name="nBytes"></param>
        /// <param name="pOutput"></param>
        /// <param name="pdwOutput"></param>
        /// <returns></returns>
        public static uint EncodeChunk(uint hbeStream, byte[] buffer, int index, uint nBytes, byte[] pOutput, ref uint pdwOutput)
        {
            uint res;
            System.Runtime.InteropServices.GCHandle handle = System.Runtime.InteropServices.GCHandle.Alloc(buffer, System.Runtime.InteropServices.GCHandleType.Pinned);
            try
            {
                IntPtr ptr = (IntPtr)(handle.AddrOfPinnedObject().ToInt32() + index);
                res = beEncodeChunk(hbeStream, nBytes / 2/*Samples*/, ptr, pOutput, ref pdwOutput);
            }
            finally
            {
                handle.Free();
            }
            return res;
        }
        /// <summary>Zakodovanie bloku</summary>
        /// <param name="hbeStream"></param>
        /// <param name="buffer"></param>
        /// <param name="pOutput"></param>
        /// <param name="pdwOutput"></param>
        /// <returns></returns>
        public static uint EncodeChunk(uint hbeStream, byte[] buffer, byte[] pOutput, ref uint pdwOutput)
        {
            return EncodeChunk(hbeStream, buffer, 0, (uint)buffer.Length, pOutput, ref pdwOutput);
        }

        public const uint BE_ERR_SUCCESSFUL = 0;
        public const uint BE_ERR_INVALID_FORMAT = 1;
        public const uint BE_ERR_INVALID_FORMAT_PARAMETERS = 2;
        public const uint BE_ERR_NO_MORE_HANDLES = 3;
        public const uint BE_ERR_INVALID_HANDLE = 4;

        protected bool FClosed;
        protected BE_CONFIG FMp3Config;
        protected uint FhLameStream;
        protected uint FInputSamples;
        protected uint FOutBufferSize;
        protected byte[] FInBuffer;
        protected int FInBufferPos;
        protected byte[] FOutBuffer;

        /// <summary>Konstruktor</summary>
        /// <param name="path">cesta</param>
        /// <param name="mode">mod</param>
        /// <param name="access">pristup</param>
        /// <param name="share">zdielanie</param>
        public IMP3WriterStream(string path, IExportCDTracks_Str pSettings, int pRate = 44100, int pBits = 16, int pChannels = 2) 
            : base (path, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.Delete)
        {
            FClosed = true;
            
            FMp3Config = new BE_CONFIG(new WaveFormat(pRate, pBits, pChannels), pSettings.MP3_BitRate);
            FMp3Config.format.lhv1.bCopyright = pSettings.MP3_Copyright ? 1 : 0;
            FMp3Config.format.lhv1.bCRC = pSettings.MP3_CRC ? 1 : 0;
            FMp3Config.format.lhv1.bOriginal = pSettings.MP3_Original ? 1 : 0;
            FMp3Config.format.lhv1.bPrivate = pSettings.MP3_Private ? 1 : 0;
            FMp3Config.format.lhv1.bEnableVBR = pSettings.MP3_UseVBR ? 1 : 0;
            if (!pSettings.MP3_UseVBR)
            {
                FMp3Config.format.lhv1.dwBitrate = pSettings.MP3_BitRate;
                FMp3Config.format.lhv1.nPreset = (LAME_QUALITY_PRESET)pSettings.MP3_Quality;
            }
            else
            {
                FMp3Config.format.lhv1.dwBitrate = pSettings.MP3_VBRAverageBitRate;
                FMp3Config.format.lhv1.dwMaxBitrate = pSettings.MP3_VBRMaxBitRate;
                FMp3Config.format.lhv1.nVbrMethod = VBRMETHOD.VBR_METHOD_DEFAULT;
                FMp3Config.format.lhv1.nVBRQuality = (int)pSettings.MP3_VBRQuality;
            }

            FhLameStream = 0;
            FInputSamples = 0;
            FOutBufferSize = 0;
            FInBuffer = null;
            FInBufferPos = 0;
            FOutBuffer = null;

            uint LameResult = beInitStream(FMp3Config, ref FInputSamples, ref FOutBufferSize, ref FhLameStream);
            if (LameResult != BE_ERR_SUCCESSFUL) throw new System.IO.IOException();

            FInBuffer = new byte[FInputSamples * 2];
            FOutBuffer = new byte[FOutBufferSize];
            FClosed = false;
        }

        /// <summary>Uzatvorenie stream</summary>
        public override void Close()
        {
            if (!FClosed)
            {
                try
                {
                    uint EncodedSize = 0;
                    if (FInBufferPos > 0)
                    {
                        if (EncodeChunk(FhLameStream, FInBuffer, 0, (uint)FInBufferPos, FOutBuffer, ref EncodedSize) == BE_ERR_SUCCESSFUL)
                        {
                            if (EncodedSize > 0)
                            {
                                base.Write(FOutBuffer, 0, (int)EncodedSize);
                            }
                        }
                    }
                    EncodedSize = 0;
                    if (beDeinitStream(FhLameStream, FOutBuffer, ref EncodedSize) == BE_ERR_SUCCESSFUL)
                    {
                        if (EncodedSize > 0)
                        {
                            base.Write(FOutBuffer, 0, (int)EncodedSize);
                        }
                    }
                }
                finally
                {
                    beCloseStream(FhLameStream);
                }
            }
            base.Close(); // Uzatvorim nadradeny stream
            FClosed = true;
        }

        /// <summary>Property: CanRead</summary>
        public override bool CanRead
        {
            get { return false; }
        }
        /// <summary>Property: CanWrite</summary>
        public override bool CanWrite
        {
            get { return true; }
        }
        /// <summary>Property: CanSeek</summary>
        public override bool CanSeek
        {
            get { return false; }
        }
        /// <summary>Property: Length</summary>
        public override long Length
        {
            get { return 0; }
        }
        /// <summary>Property: Position</summary>
        public override long Position
        {
            get { return 0; }
            set
            {
            }
        }

        /// <summary>Metoda: Flush</summary>
        public override void Flush()
        {
        }
        /// <summary>Metoda: Seek</summary>
        /// <param name="offset">offset</param>
        /// <param name="origin">zaciatok posunu</param>
        /// <returns>vysledok</returns>
        public override long Seek(long offset, System.IO.SeekOrigin origin)
        {
            return 0;
        }
        /// <summary>Metoda: SetLength</summary>
        /// <param name="value">hodnota</param>
        public override void SetLength(long value)
        {
        }
        /// <summary>Metoda: Read</summary>
        /// <param name="buffer">buffer</param>
        /// <param name="offset">zaciatok v bufri</param>
        /// <param name="count">pocet</param>
        /// <returns>pocet nacitanych bajtov</returns>
        public override int Read(byte[] buffer, int offset, int count)
        {
            return 0;
        }
        /// <summary>Metoda: Write</summary>
        /// <param name="buffer">buffer</param>
        /// <param name="offset">zaciatok v bufri</param>
        /// <param name="count">pocet</param>
        public override void Write(byte[] buffer, int offset, int count)
        {
            int ToCopy = 0;
            uint EncodedSize = 0;
            uint LameResult;
            while (count > 0)
            {
                if (FInBufferPos > 0)
                {
                    ToCopy = Math.Min(count, FInBuffer.Length - FInBufferPos);
                    Buffer.BlockCopy(buffer, offset, FInBuffer, FInBufferPos, ToCopy);
                    FInBufferPos += ToCopy;
                    offset += ToCopy;
                    count -= ToCopy;
                    if (FInBufferPos >= FInBuffer.Length)
                    {
                        FInBufferPos = 0;
                        if ((LameResult = EncodeChunk(FhLameStream, FInBuffer, FOutBuffer, ref EncodedSize)) == BE_ERR_SUCCESSFUL)
                        {
                            if (EncodedSize > 0)
                            {
                                base.Write(FOutBuffer, 0, (int)EncodedSize);
                            }
                        }
                        else
                        {
                            throw new System.IO.IOException();
                        }
                    }
                }
                else
                {
                    if (count >= FInBuffer.Length)
                    {
                        if ((LameResult = EncodeChunk(FhLameStream, buffer, offset, (uint)FInBuffer.Length, FOutBuffer, ref EncodedSize)) == BE_ERR_SUCCESSFUL)
                        {
                            if (EncodedSize > 0)
                            {
                                base.Write(FOutBuffer, 0, (int)EncodedSize);
                            }
                        }
                        else
                        {
                            throw new System.IO.IOException();
                        }
                        count -= FInBuffer.Length;
                        offset += FInBuffer.Length;
                    }
                    else
                    {
                        Buffer.BlockCopy(buffer, offset, FInBuffer, 0, count);
                        FInBufferPos = count;
                        offset += count;
                        count = 0;
                    }
                }
            }
        }
    }

    /// <summary>Trieda IFileExplorerForm_ExportCDTracks</summary>
    public class IFileExplorerForm_ExportCDTracks : IForm
    {
        protected delegate void Delegate_StopLoadTracks();
        protected delegate void Delegate_UpdateStatus(int pTrackIndex, ulong pReaded, ulong pTotalSize);
        protected delegate void Delegate_SetOneStatus(int pIndex, string pState);

        public static IFileExplorerForm_ExportCDTracks FormInstance = null;

        protected IGroupBox FGrp; // Controls
        protected IButton FBtn_Cancel;
        protected IButton FBtn_Reload;
        protected IButton FBtn_Settings;

        protected IComboBox FCombo_Drives;
        protected IListView FList;
        protected ISimpleStatusStrip FStatus;

        protected System.Threading.Thread FWorkThread; // Aktualny thread
        protected int FWorkMode; // Mod spracovania
        protected System.Collections.Generic.List<core2namespace.ITrackItem> FCurrentItems;
        protected IExportCDTracks_Str FSettings; // Nastavenie
        protected bool FWantToTerminate;

        /// <summary>Property: CurrentChoosedDevice</summary>
        protected char CurrentChoosedDevice
        {
            get
            {
                if (FCombo_Drives.SelectedIndex == -1) return (char)0;
                return FCombo_Drives.SelectedStringID[0];
            }
        }
        /// <summary>Property: AudioTracksCount</summary>
        protected int AudioTracksCount
        {
            get
            {
                int C = 0;
                foreach (core2namespace.ITrackItem I in FCurrentItems)
                {
                    if (I.IsAudioTrack()) C++;
                }
                return C;
            }
        }
        /// <summary>Property: DataTracksCount</summary>
        protected int DataTracksCount
        {
            get
            {
                int C = 0;
                foreach (core2namespace.ITrackItem I in FCurrentItems)
                {
                    if (!I.IsAudioTrack()) C++;
                }
                return C;
            }
        }
        /// <summary>Property: MediumType</summary>
        protected string MediumType
        {
            get
            {
                int C1 = AudioTracksCount; int C2 = DataTracksCount;
                if (C1 > 0)
                {
                    return C2 == 0 ? lang.FORM_EXPORT_CD_TRACKS_TEXT_7_4 : lang.FORM_EXPORT_CD_TRACKS_TEXT_7_6;
                }
                else
                {
                    return C1 == 0 ? lang.FORM_EXPORT_CD_TRACKS_TEXT_7_5 : lang.FORM_EXPORT_CD_TRACKS_TEXT_7_6;
                }
            }
        }
        /// <summary>Property: SelectedCount</summary>
        protected int SelectedCount
        {
            get
            {
                int C = 0;
                foreach (IListViewItem LI in FList.Items)
                {
                    if (LI.Checked) C++; // Ak je oznacene
                }
                return C; // Vratim pocet
            }
        }

        /// <summary>Property: CanCloseForm</summary>
        public override bool CanCloseForm
        {
            get
            {
                return FWorkMode == 0;
            }
        }

        /// <summary>Konstruktor</summary>
        public IFileExplorerForm_ExportCDTracks()
        {
            FormInstance = this; // Ulozim instanciu

            FWorkThread = null;
            FWorkMode = 0;
            FCurrentItems = new System.Collections.Generic.List<core2namespace.ITrackItem>();
            FSettings = new IExportCDTracks_Str(); FSettings.Deserialize(IApp.GlobalData.FileExplorer_ExtractCDContentSettings);
        }

        /// <summary>Metoda: OnCreateForm</summary>
        /// <returns>true / false</returns>
        protected override bool OnCreateForm()
        {
            if (!base.OnCreateForm()) return false; // Volam predchodcu

            // Inicializacia
            MinimizeBox = false; MaximizeBox = false; FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; ShowIcon = true; ShowInTaskbar = true; StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;

            SetBounds(0, 0, 700, 540); System.Drawing.Size CS = ClientSize;
            Text = lang.FORM_EXPORT_CD_TRACKS_TEXT_1;

            // Vytvorim groupbox
            FGrp = new IGroupBox(); IControl.PlaceControl_Inside(FGrp, this, 10, 10, 10, 50);
            // Vytvorim tlacidla
            FBtn_Cancel = new IButton(lang.FORM_EXPORT_CD_TRACKS_TEXT_2, Event_BtnCancelClick); IControl.PlaceControl_Outside_TopRight_RightBottom(FBtn_Cancel, FGrp, 0, 10);
            FBtn_Reload = new IButton(lang.FORM_EXPORT_CD_TRACKS_TEXT_2_2, Event_BtnReloadClick); IControl.PlaceControl_Outside_TopRight_LeftTop(FBtn_Reload, FBtn_Cancel, 0, 10);
            FBtn_Settings = new IButton(lang.FORM_EXPORT_CD_TRACKS_TEXT_2_3, Event_BtnSettingsClick); IControl.PlaceControl_Outside_LeftTop_LeftBottom(FBtn_Settings, FGrp, 0, 10);
            Controls.AddRange(new System.Windows.Forms.Control[] { FGrp, FBtn_Settings, FBtn_Reload, FBtn_Cancel }); // Zaradim do controls

            FCombo_Drives = new IComboBox(); FCombo_Drives.Dock = System.Windows.Forms.DockStyle.Top;
            FList = new IListView(); FList.MultiSelect = false; FList.FullRowSelect = true; FList.CheckBoxes = true; FList.Dock = System.Windows.Forms.DockStyle.Fill;
            FList.HideSelection = false;
            FList.CreateColumn(lang.FORM_EXPORT_CD_TRACKS_TEXT_3_1, 280, System.Windows.Forms.HorizontalAlignment.Left);
            FList.CreateColumn(lang.FORM_EXPORT_CD_TRACKS_TEXT_3_4, 120, System.Windows.Forms.HorizontalAlignment.Left);
            FList.CreateColumn(lang.FORM_EXPORT_CD_TRACKS_TEXT_3_2, 100, System.Windows.Forms.HorizontalAlignment.Right);
            FList.CreateColumn(lang.FORM_EXPORT_CD_TRACKS_TEXT_3_3, 100, System.Windows.Forms.HorizontalAlignment.Center);

            FList.ContextMenuStrip = new System.Windows.Forms.ContextMenuStrip();
            CreateMenu(FList.ContextMenuStrip.Items); // Vytvorim menu

            FStatus = new ISimpleStatusStrip(); FStatus.Dock = System.Windows.Forms.DockStyle.Bottom;

            FGrp.Controls.AddRange(new System.Windows.Forms.Control[] { FCombo_Drives, FStatus, FList }); FList.BringToFront();

            FCombo_Drives.SelectedValueChanged += (s, e) =>
            {
                StartLoadTracks(CurrentChoosedDevice);
            };
            
            KeyDown += Event_KeyDown;
            FCombo_Drives.KeyDown += Event_KeyDown;
            FList.KeyDown += Event_KeyDown;
            FBtn_Cancel.KeyDown += Event_KeyDown;
            FBtn_Reload.KeyDown += Event_KeyDown;
            FBtn_Settings.KeyDown += Event_KeyDown;

            LoadDriveList(); // Nacitam zariadenia
            return true; // Vsetko OK
        }

        /// <summary>Metoda: OnClosing</summary>
        /// <param name="e">parameter</param>
        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            if (FWorkMode != 0) e.Cancel = true; 
        }
        /// <summary>Metoda: OnClosed</summary>
        /// <param name="e">parameter</param>
        protected override void OnClosed(EventArgs e)
        {
            IApp.GlobalData.FileExplorer_ExtractCDContentSettings = FSettings.Serialize();
            Dispose(); FormInstance = null;
        }

        /// <summary>Nacitanie zoznamu CD/DVD zariadeni</summary>
        protected void LoadDriveList()
        {
            FCombo_Drives.Items.Clear();
            try
            {
                System.Management.ManagementObjectSearcher Search = new System.Management.ManagementObjectSearcher("Select Drive, Name from Win32_CDROMDrive");
                
                System.Collections.Generic.List<System.Management.ManagementObject> L = new System.Collections.Generic.List<System.Management.ManagementObject>();
                foreach (System.Management.ManagementObject obj in Search.Get()) L.Add(obj); // Vytvorim zoznam
                // Zotriedim podla pismena disku
                L.Sort(delegate(System.Management.ManagementObject pObj1, System.Management.ManagementObject pObj2)
                {
                    return string.Compare(pObj1.GetPropertyValue("Drive").ToString(), pObj2.GetPropertyValue("Drive").ToString(), true);
                });

                foreach(System.Management.ManagementObject obj in L) // Vyplnim combobox
                {
                    FCombo_Drives.AddItem(string.Format("{0} [{1}]", obj.GetPropertyValue("Drive").ToString(), obj.GetPropertyValue("Name").ToString()), obj.GetPropertyValue("Drive").ToString() + "\\");
                }

                if (FCombo_Drives.Items.Count > 0) FCombo_Drives.SelectedIndex = 0; // Nastavim sa na prvy zaznam
            }
            catch
            {
            }
        }

        /// <summary>Nacitanie zoznamu stop</summary>
        protected void StartLoadTracks(char pDriveLetter)
        {
            if (pDriveLetter == 0) return; // Nepripustne zariadenie?

            FList.BeginCreate();
            FList.Items.Clear();
            FList.Enabled = false;
            FCombo_Drives.Enabled = false;
            FStatus.SimpleText = lang.FORM_EXPORT_CD_TRACKS_TEXT_5;

            FWorkThread = new System.Threading.Thread(delegate()
            {
                FCurrentItems.Clear(); // Zrusim aktualny zoznam
                using (core2namespace.ICDDriveReaded Reader = new core2namespace.ICDDriveReaded())
                {
                    Reader.DefaultTrackName = lang.FORM_EXPORT_CD_TRACKS_TEXT_4;
                    if (Reader.Open(pDriveLetter) == 0) // Otvorim mechaniku
                    {
                        if (Reader.ReadTrackList() == 0)
                        {
                            int C = Reader.TracksCount;
                            for (int i = 0; i < C; i++)
                            {
                                FCurrentItems.Add(new core2namespace.ITrackItem(Reader[i]));
                            }
                        }
                    }
                }
                FWorkThread = null;
                StopLoadTracks(); // Ukoncim nacitavanie
            });

            FBtn_Cancel.Text = lang.FORM_EXPORT_CD_TRACKS_TEXT_2_1;
            FBtn_Reload.Enabled = false;
            FBtn_Settings.Enabled = false;

            FWorkThread.IsBackground = true; FWorkThread.Priority = System.Threading.ThreadPriority.Lowest; FWorkThread.SetApartmentState(System.Threading.ApartmentState.STA);
            FWorkThread.Start();
            FWorkMode = 1;// Mod nacitavania obsahu
        }
        /// <summary>Zastavenie procesu nacitavania obsahu</summary>
        protected void StopLoadTracks()
        {
            if (InvokeRequired) // Je potrebne invoke?
            {
                Invoke(new Delegate_StopLoadTracks(StopLoadTracks));
                return;
            }

            while (FWorkThread != null) System.Threading.Thread.Sleep(10);

            for (int i = 0; i < FCurrentItems.Count; i++)
            {
                IListViewItem LI = FList.AddItem(null, FCurrentItems[i].TrackName, i);
                if ((FCurrentItems[i].TrackType & 0x4) == 0x4) LI.SubItems[1].Text = lang.FORM_EXPORT_CD_TRACKS_TEXT_7_1;
                else LI.SubItems[1].Text = lang.FORM_EXPORT_CD_TRACKS_TEXT_7_2;
                if (FCurrentItems[i].IsAudioTrack()) LI.SubItems[2].Text = ICore.Miliseconds2DispString(FCurrentItems[i].TrackLengthInTime);
                else LI.SubItems[2].Text = ICore.Size2String((ulong)FCurrentItems[i].TrackLength * (ulong)FCurrentItems[i].GetSectorSize(), 1);
            }
            FList.EndCreate(0);
            FList.Enabled = true;
            FCombo_Drives.Enabled = true;
            UpdateStatus();
            
            FWorkMode = 0; // Mod bez aktivneho spracovania
            
            FBtn_Cancel.Text = lang.FORM_EXPORT_CD_TRACKS_TEXT_2;
            FBtn_Reload.Enabled = true;
            FBtn_Settings.Enabled = true;
        }
        /// <summary>Aktualizacia statusu</summary>
        protected void UpdateStatus()
        {
            string S;
            if (FCurrentItems.Count == 0) S = lang.FORM_EXPORT_CD_TRACKS_TEXT_6; // Chyba?
            else S = string.Format(lang.FORM_EXPORT_CD_TRACKS_TEXT_7_3, MediumType, FSettings.OutputPath);
            FStatus.SimpleText = S;
            
        }
        /// <summary>Vytvorenie menu</summary>
        /// <param name="pParent">rodicovska kolekcia</param>
        protected void CreateMenu(System.Windows.Forms.ToolStripItemCollection pParent)
        {
            pParent.Clear(); // Zrusim aktualny obsah

            IToolStripMenuItem M1, M2, M3, M4;
            IToolStrip.CreateMenuItem(pParent, lang.FORM_EXPORT_CD_TRACKS_TEXT_8_7, Event_MIClick_Start);
            IToolStrip.CreateSeparator(pParent);
            M1 = IToolStrip.CreateMenuItem(pParent, lang.FORM_EXPORT_CD_TRACKS_TEXT_8_5);
            M2 = M1.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_3);
            M3 = M2.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_3_1, Event_MIClick_Settings_1); M3.Tag = IExportCDTracks_Str.OUTPUT_TYPE_AUDIO_WAV; M3.Checked = FSettings.OutputTypeAudio == IExportCDTracks_Str.OUTPUT_TYPE_AUDIO_WAV;
            M3 = M2.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_3_2, Event_MIClick_Settings_1); M3.Tag = IExportCDTracks_Str.OUTPUT_TYPE_AUDIO_MP3; M3.Checked = FSettings.OutputTypeAudio == IExportCDTracks_Str.OUTPUT_TYPE_AUDIO_MP3;
            
            M2 = M1.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_3);
            M2.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_4_1).Checked = FSettings.OutputTypeData == IExportCDTracks_Str.OUTPUT_TYPE_DATA_ISO;
            M1.CreateSeparator();
            M2 = M1.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9);

            M3 = M2.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_1);
            M4 = M3.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_1_1, Event_MIClick_Settings_2); M4.Tag = 128; M4.Checked = (!FSettings.MP3_UseVBR) && (FSettings.MP3_BitRate == 128);
            M4 = M3.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_1_2, Event_MIClick_Settings_2); M4.Tag = 192; M4.Checked = (!FSettings.MP3_UseVBR) && (FSettings.MP3_BitRate == 192);
            M4 = M3.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_1_3, Event_MIClick_Settings_2); M4.Tag = 256; M4.Checked = (!FSettings.MP3_UseVBR) && (FSettings.MP3_BitRate == 256);
            M4 = M3.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_1_4, Event_MIClick_Settings_2); M4.Tag = 320; M4.Checked = (!FSettings.MP3_UseVBR) && (FSettings.MP3_BitRate == 320);
            M3.CreateSeparator();
            M4 = M3.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_1_5, Event_MIClick_Settings_2); M4.Tag = 0; M4.Checked = FSettings.MP3_UseVBR;

            M3 = M2.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_2);
            M4 = M3.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_2_1, Event_MIClick_Settings_3); M4.Tag = IMP3WriterStream.LAME_QUALITY_PRESET.LQP_LOW_QUALITY; M4.Checked = FSettings.MP3_Quality == (uint)IMP3WriterStream.LAME_QUALITY_PRESET.LQP_LOW_QUALITY;
            M4 = M3.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_2_2, Event_MIClick_Settings_3); M4.Tag = IMP3WriterStream.LAME_QUALITY_PRESET.LQP_NORMAL_QUALITY; M4.Checked = FSettings.MP3_Quality == (uint)IMP3WriterStream.LAME_QUALITY_PRESET.LQP_NORMAL_QUALITY;
            M4 = M3.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_2_3, Event_MIClick_Settings_3); M4.Tag = IMP3WriterStream.LAME_QUALITY_PRESET.LQP_HIGH_QUALITY; M4.Checked = FSettings.MP3_Quality == (uint)IMP3WriterStream.LAME_QUALITY_PRESET.LQP_HIGH_QUALITY;
            M4 = M3.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_2_4, Event_MIClick_Settings_3); M4.Tag = IMP3WriterStream.LAME_QUALITY_PRESET.LQP_VERYHIGH_QUALITY; M4.Checked = FSettings.MP3_Quality == (uint)IMP3WriterStream.LAME_QUALITY_PRESET.LQP_VERYHIGH_QUALITY;

            M2.CreateSeparator();
            M3 = M2.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_3);
            M4 = M3.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_3_1, Event_MIClick_Settings_4); M4.Tag = 0; M4.Checked = FSettings.MP3_Copyright;
            M4 = M3.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_3_2, Event_MIClick_Settings_4); M4.Tag = 1; M4.Checked = FSettings.MP3_CRC;
            M4 = M3.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_3_3, Event_MIClick_Settings_4); M4.Tag = 2; M4.Checked = FSettings.MP3_Private;
            M4 = M3.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_9_3_4, Event_MIClick_Settings_4); M4.Tag = 3; M4.Checked = FSettings.MP3_Original;

            M1.CreateSeparator();
            M1.CreateMenuItem(lang.FORM_EXPORT_CD_TRACKS_TEXT_8_6, Event_MIClick_ChooseDestPath);

            IToolStrip.CreateSeparator(pParent);
            IToolStrip.CreateMenuItem(pParent, lang.FORM_EXPORT_CD_TRACKS_TEXT_8_1, Event_MIClick_SelectAll);
            IToolStrip.CreateMenuItem(pParent, lang.FORM_EXPORT_CD_TRACKS_TEXT_8_2, Event_MIClick_DeselectAll);
            IToolStrip.CreateSeparator(pParent);
            IToolStrip.CreateMenuItem(pParent, lang.FORM_EXPORT_CD_TRACKS_TEXT_8_8, Event_MIClick_OpenDestPath);
        }
        /// <summary>Zaciatok citania stop</summary>
        protected void StartReadTracks()
        {
            FCombo_Drives.Enabled = false;
            char CurrentLetter = CurrentChoosedDevice;

            int[] TrackIndices = new int[SelectedCount];
            int i = 0;
            for (int j = 0; j < FCurrentItems.Count; j++)
            {
                if (FList.Items[j].Checked) TrackIndices[i++] = j;
            }
            FWantToTerminate = false;

            FWorkThread = new System.Threading.Thread(delegate()
            {
                using (core2namespace.ICDDriveReaded Reader = new core2namespace.ICDDriveReaded())
                {
                    Reader.DefaultTrackName = lang.FORM_EXPORT_CD_TRACKS_TEXT_4;
                    if (Reader.Open(CurrentLetter) == 0) // Otvorim mechaniku
                    {
                        if (Reader.ReadTrackList() == 0) // Nacitam zoznam stop
                        {
                            foreach (int Idx in TrackIndices) // Prejdem vsetky stopy
                            {
                                if (FCurrentItems[Idx].IsAudioTrack()) // Audio stopa?
                                {
                                    if (Reader.OpenAudioTrackForRead(Idx) == 0) // Otvorim stopu na citanie
                                    {
                                        string FN = CreateTrackFileName(Idx);
                                        try
                                        {
                                            System.IO.Stream OutStream;
                                            ulong TotalLength = FCurrentItems[Idx].TrackLength * (ulong)FCurrentItems[Idx].GetSectorSize();
                                            switch (FSettings.OutputTypeAudio)
                                            {
                                                case IExportCDTracks_Str.OUTPUT_TYPE_AUDIO_MP3:
                                                    {
                                                        try
                                                        {
                                                            OutStream = new IMP3WriterStream(FN, FSettings, 44100, 16, 2);
                                                        }
                                                        catch
                                                        {
                                                            Reader.CloseAudioTrackForRead(); 
                                                            IApp.ShowError(string.Format(lang.FORM_EXPORT_CD_TRACKS_TEXT_15, Idx + 1));
                                                            FWorkThread = null;
                                                            StopReadTracks(); // Ukoncim nacitavanie
                                                            return;
                                                        }
                                                    } break;
                                                default: // WAV subor
                                                    {
                                                        try
                                                        {
                                                            OutStream = new IWAVWriterStream(FN, 44100, 16, 2, (uint)TotalLength);
                                                        }
                                                        catch
                                                        {
                                                            Reader.CloseAudioTrackForRead(); 
                                                            IApp.ShowError(string.Format(lang.FORM_EXPORT_CD_TRACKS_TEXT_15, Idx + 1));
                                                            FWorkThread = null;
                                                            StopReadTracks(); // Ukoncim nacitavanie
                                                            return;
                                                        }
                                                    } break;
                                            }

                                            using (OutStream)
                                            {
                                                if (IFileSystem.GetDeviceFreeSpace(FSettings.OutputPath) <= (long)TotalLength + 1024) // Je dostatok miesta?
                                                {
                                                    Reader.CloseAudioTrackForRead(); OutStream.Close(); IFileSystem.DeleteFile(FN);
                                                    IApp.ShowError(string.Format(lang.FORM_EXPORT_CD_TRACKS_TEXT_17, Idx + 1));
                                                    FWorkThread = null;
                                                    StopReadTracks(); // Ukoncim nacitavanie
                                                    return;
                                                }

                                                byte[] Buffer = new byte[Reader.ReadBufferLength];
                                                ulong Readed = 0;

                                                UpdateStatus(Idx + 1, Readed, TotalLength);
                                                SetOneStatus(Idx, lang.FORM_EXPORT_CD_TRACKS_TEXT_12);

                                                while (true) // Citam stopu
                                                {
                                                    if (FWantToTerminate)
                                                    {
                                                        Reader.CloseAudioTrackForRead(); OutStream.Close(); IFileSystem.DeleteFile(FN);
                                                        FWorkThread = null;
                                                        StopReadTracks(); // Ukoncim nacitavanie
                                                        return;
                                                    }
                                                    int C = Reader.ReadAudioTrack(Buffer, 0, Buffer.Length);
                                                    if (C == 0) break;
                                                    if (C < 0)
                                                    {
                                                        Reader.CloseAudioTrackForRead(); OutStream.Close(); IFileSystem.DeleteFile(FN);
                                                        IApp.ShowError(string.Format(lang.FORM_EXPORT_CD_TRACKS_TEXT_10, Idx + 1));
                                                        FWorkThread = null;
                                                        StopReadTracks(); // Ukoncim nacitavanie
                                                        return;
                                                    }

                                                    try
                                                    {
                                                        OutStream.Write(Buffer, 0, C); // Zapisem do vystupu
                                                    }
                                                    catch
                                                    {
                                                        Reader.CloseAudioTrackForRead(); OutStream.Close(); IFileSystem.DeleteFile(FN);
                                                        IApp.ShowError(string.Format(lang.FORM_EXPORT_CD_TRACKS_TEXT_15, Idx + 1));
                                                        FWorkThread = null;
                                                        StopReadTracks(); // Ukoncim nacitavanie
                                                        return;
                                                    }

                                                    Readed += (ulong)C;
                                                    if (Readed >= TotalLength) break;
                                                    UpdateStatus(Idx + 1, Readed, TotalLength);
                                                }
                                                Reader.CloseAudioTrackForRead();
                                                OutStream.Close();
                                                SetOneStatus(Idx, lang.FORM_EXPORT_CD_TRACKS_TEXT_13);
                                            }
                                        }
                                        catch
                                        {
                                            IFileSystem.DeleteFile(FN);
                                            Reader.CloseAudioTrackForRead();
                                            IApp.ShowError(string.Format(lang.FORM_EXPORT_CD_TRACKS_TEXT_10, Idx + 1));
                                            FWorkThread = null;
                                            StopReadTracks(); // Ukoncim nacitavanie
                                            return;
                                        }
                                    }
                                }
                                else // Datova stopa
                                {
                                    if (Reader.OpenDataTrackForRead(Idx) == 0) // Otvorim stopu na citanie
                                    {
                                        string FN = CreateTrackFileName(Idx);
                                        try
                                        {
                                            System.IO.Stream OutStream;
                                            switch (FSettings.OutputTypeData)
                                            {
                                                default: // ISO subor
                                                    {
                                                        FN = IApp.ShowEditor_ChooseFileSave(lang.FORM_EXPORT_CD_TRACKS_TEXT_18, lang.FORM_EXPORT_CD_TRACKS_TEXT_18_1, "", FN);
                                                        if (string.IsNullOrEmpty(FN))
                                                        {
                                                            Reader.CloseDataTrackForRead();
                                                            FWorkThread = null;
                                                            StopReadTracks(); // Ukoncim nacitavanie
                                                            return;
                                                        }
                                                        OutStream = new System.IO.FileStream(FN, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None);
                                                    } break;
                                            }

                                            using (OutStream)
                                            {
                                                ulong TotalLength = FCurrentItems[Idx].TrackLength * (ulong)FCurrentItems[Idx].GetSectorSize();
                                                if (IFileSystem.GetDeviceFreeSpace(FSettings.OutputPath) <= (long)TotalLength + 1024) // Je dostatok miesta?
                                                {
                                                    Reader.CloseDataTrackForRead(); OutStream.Close(); IFileSystem.DeleteFile(FN);
                                                    IApp.ShowError(string.Format(lang.FORM_EXPORT_CD_TRACKS_TEXT_17, Idx + 1));
                                                    FWorkThread = null;
                                                    StopReadTracks(); // Ukoncim nacitavanie
                                                    return;
                                                }

                                                byte[] Buffer = new byte[Reader.ReadBufferLength];
                                                ulong Readed = 0;

                                                UpdateStatus(Idx + 1, Readed, TotalLength);
                                                SetOneStatus(Idx, lang.FORM_EXPORT_CD_TRACKS_TEXT_12);

                                                while (true) // Citam stopu
                                                {
                                                    if (FWantToTerminate)
                                                    {
                                                        Reader.CloseDataTrackForRead(); OutStream.Close(); IFileSystem.DeleteFile(FN);
                                                        FWorkThread = null;
                                                        StopReadTracks(); // Ukoncim nacitavanie
                                                        return;
                                                    }
                                                    int C = Reader.ReadDataTrack(Buffer, 0, Buffer.Length);
                                                    if (C == 0) break;
                                                    if (C < 0)
                                                    {
                                                        Reader.CloseDataTrackForRead(); OutStream.Close(); IFileSystem.DeleteFile(FN);
                                                        IApp.ShowError(string.Format(lang.FORM_EXPORT_CD_TRACKS_TEXT_10, Idx + 1));
                                                        FWorkThread = null;
                                                        StopReadTracks(); // Ukoncim nacitavanie
                                                        return;
                                                    }

                                                    try
                                                    {
                                                        OutStream.Write(Buffer, 0, C); // Zapisem do vystupu
                                                    }
                                                    catch
                                                    {
                                                        Reader.CloseDataTrackForRead(); OutStream.Close(); IFileSystem.DeleteFile(FN);
                                                        IApp.ShowError(string.Format(lang.FORM_EXPORT_CD_TRACKS_TEXT_15, Idx + 1));
                                                        FWorkThread = null;
                                                        StopReadTracks(); // Ukoncim nacitavanie
                                                        return;
                                                    }

                                                    Readed += (ulong)C;
                                                    if (Readed >= TotalLength) break;
                                                    UpdateStatus(Idx + 1, Readed, TotalLength);
                                                }
                                                Reader.CloseDataTrackForRead();
                                                OutStream.Close();
                                                SetOneStatus(Idx, lang.FORM_EXPORT_CD_TRACKS_TEXT_13);
                                            }
                                        }
                                        catch
                                        {
                                            IFileSystem.DeleteFile(FN);
                                            Reader.CloseDataTrackForRead();
                                            IApp.ShowError(string.Format(lang.FORM_EXPORT_CD_TRACKS_TEXT_10, Idx + 1));
                                            FWorkThread = null;
                                            StopReadTracks(); // Ukoncim nacitavanie
                                            return;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                FWorkThread = null;
                StopReadTracks(); // Ukoncim nacitavanie
            });

            FBtn_Cancel.Text = lang.FORM_EXPORT_CD_TRACKS_TEXT_2_1;
            FBtn_Reload.Enabled = false;
            FBtn_Settings.Enabled = false;
            FList.Enabled = false;
            SetAllSelectedStates(lang.FORM_EXPORT_CD_TRACKS_TEXT_11);

            FWorkThread.IsBackground = true; FWorkThread.Priority = System.Threading.ThreadPriority.Lowest; FWorkThread.SetApartmentState(System.Threading.ApartmentState.STA);
            FWorkThread.Start();
            FWorkMode = 2; // Mod nacitavania obsahu
        }
        /// <summary>Zastavenie procesu nacitavania obsahu</summary>
        protected void StopReadTracks()
        {
            if (InvokeRequired) // Je potrebne invoke?
            {
                Invoke(new Delegate_StopLoadTracks(StopReadTracks));
                return;
            }

            while (FWorkThread != null) System.Threading.Thread.Sleep(10);

            FList.Enabled = true;
            FCombo_Drives.Enabled = true;
            UpdateStatus();

            FWorkMode = 0; // Mod bez aktivneho spracovania

            FBtn_Cancel.Text = lang.FORM_EXPORT_CD_TRACKS_TEXT_2;
            FBtn_Reload.Enabled = true;
            FBtn_Settings.Enabled = true;
            SetAllStates(""); // Zrusim stavy
        }
        /// <summary>Nastavenie stavu vsetkych stop</summary>
        /// <param name="pText">text</param>
        protected void SetAllStates(string pText)
        {
            foreach (IListViewItem LI in FList.Items)
            {
                LI.SubItems[3].Text = pText;
            }
        }
        /// <summary>Nastavenie stavu vsetkych oznacenych stop</summary>
        /// <param name="pText">text</param>
        protected void SetAllSelectedStates(string pText)
        {
            foreach (IListViewItem LI in FList.Items)
            {
                if (LI.Checked) LI.SubItems[3].Text = pText;
            }
        }
        /// <summary>Aktualizacia statusu pri spracovani citania</summary>
        /// <param name="pTrackIndex">cislo stopy</param>
        /// <param name="pReaded">precitane</param>
        /// <param name="pTotalSize">celkova velkost</param>
        protected void UpdateStatus(int pTrackIndex, ulong pReaded, ulong pTotalSize)
        {
            if (InvokeRequired)
            {
                Invoke(new Delegate_UpdateStatus(UpdateStatus), new object[] { pTrackIndex, pReaded, pTotalSize });
                return;
            }
            FStatus.SimpleText = string.Format(lang.FORM_EXPORT_CD_TRACKS_TEXT_14, pTrackIndex, ICore.Size2String(pReaded, 1), ICore.Size2String(pTotalSize, 1));
        }
        /// <summary>Vytvorenie nazvu stopy</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>nazov</returns>
        protected string CreateTrackFileName(int pIndex)
        {
            string S;
            if (FCurrentItems[pIndex].IsAudioTrack()) S = string.Format("{0:D3}_track.{1}", pIndex + 1, IExportCDTracks_Str.GetExtension(FSettings.OutputTypeAudio));
            else S = string.Format("image_{1}.{0}", IExportCDTracks_Str.GetExtension(FSettings.OutputTypeData), DateTime.Now.ToString("ddMMyyyyHHmmss"));
            return IFileSystem.AppendToPath(FSettings.OutputPath, S);
        }
        /// <summary>Nastavenie statusu zadanej polozky</summary>
        /// <param name="pIndex">pozicia</param>
        /// <param name="pState">status</param>
        protected void SetOneStatus(int pIndex, string pState)
        {
            if (InvokeRequired) // Invoke?
            {
                Invoke(new Delegate_SetOneStatus(SetOneStatus), new object[] { pIndex, pState });
                return;
            }
            try
            {
                IListViewItem LI = (IListViewItem)FList.Items[pIndex];
                LI.SubItems[3].Text = pState;
                LI.EnsureVisible();
            }
            catch
            {
            }
        }

        /// <summary>Event: OnClick pre tlacidlo 'close'</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_BtnCancelClick(object pSender, EventArgs e)
        {
            switch (FWorkMode)
            {
                case 2:
                    {
                        FWantToTerminate = true;
                    } break;
                default:
                    {
                        Close(); // Uzatvorim okno
                    } break;
            }
        }
        /// <summary>Event: OnClick pre tlacidlo 'reload'</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_BtnReloadClick(object pSender, EventArgs e)
        {
            StartLoadTracks(CurrentChoosedDevice);
        }
        /// <summary>Event: OnClick pre polozku menu 'Oznacit vsetky'</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_MIClick_SelectAll(object pSender, EventArgs e)
        {
            foreach(IListViewItem LI in FList.Items) 
            {
                LI.Checked = true;
            }
        }
        /// <summary>Event: OnClick pre polozku menu 'Odznacit vsetky'</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_MIClick_DeselectAll(object pSender, EventArgs e)
        {
            foreach (IListViewItem LI in FList.Items)
            {
                LI.Checked = false;
            }
        }
        /// <summary>Event: OnClick pre tlacidlo 'Nastavenie'</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_BtnSettingsClick(object pSender, EventArgs e)
        {
            FList.ContextMenuStrip.Show(FBtn_Settings, 10, 10);
        }
        /// <summary>Event: OnClick pre polozku menu 'Spustit extrahovanie'</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_MIClick_Start(object pSender, EventArgs e)
        {
            if (SelectedCount == 0)
            {
                IApp.ShowError(lang.FORM_EXPORT_CD_TRACKS_TEXT_9);
                return;
            }
            StartReadTracks();
        }
        /// <summary>Event: OnClick pre polozku menu 'Vybrat vystupny priecinok'</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_MIClick_ChooseDestPath(object pSender, EventArgs e)
        {
            string FN = IApp.ShowEditor_ChooseDirectory(lang.FORM_EXPORT_CD_TRACKS_TEXT_16, FSettings.OutputPath);
            if (!string.IsNullOrEmpty(FN)) FSettings.OutputPath = FN;
            UpdateStatus();
        }
        /// <summary>Event: OnClick pre polozku menu 'Otvorit vystupny priecinok'</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_MIClick_OpenDestPath(object pSender, EventArgs e)
        {
            IApp.RunFile(FSettings.OutputPath);
        }
        /// <summary>Event: OnClick pre polozku menu 'Nastavit vystupny typ audio suboru'</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_MIClick_Settings_1(object pSender, EventArgs e)
        {
            FSettings.OutputTypeAudio = ICore.ToInt(((IToolStripMenuItem)pSender).Tag);
            CreateMenu(FList.ContextMenuStrip.Items);
        }
        /// <summary>Event: OnClick pre polozku menu 'Nastavit kvalitu MP3 (kbits)'</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_MIClick_Settings_2(object pSender, EventArgs e)
        {
            int T = ICore.ToInt(((IToolStripMenuItem)pSender).Tag);
            switch (T)
            {
                case 128:
                case 192:
                case 256:
                case 320:
                    {
                        FSettings.MP3_BitRate = (uint)T;
                        FSettings.MP3_UseVBR = false;
                    } break;
                default:
                    {
                        FSettings.MP3_VBRAverageBitRate = 128;
                        FSettings.MP3_VBRMaxBitRate = 320;
                        FSettings.MP3_VBRQuality = 9;
                        FSettings.MP3_UseVBR = true;
                    } break;
            }
            CreateMenu(FList.ContextMenuStrip.Items);
        }
        /// <summary>Event: OnClick pre polozku menu 'Nastavit kvalitu MP3 (kodovanie)'</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_MIClick_Settings_3(object pSender, EventArgs e)
        {
            FSettings.MP3_Quality = (uint)ICore.ToInt(((IToolStripMenuItem)pSender).Tag);
            CreateMenu(FList.ContextMenuStrip.Items);
        }
        /// <summary>Event: OnClick pre polozku menu 'Nastavit bitove priznaky'</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_MIClick_Settings_4(object pSender, EventArgs e)
        {
            switch (ICore.ToInt(((IToolStripMenuItem)pSender).Tag))
            {
                case 0: FSettings.MP3_Copyright = !FSettings.MP3_Copyright; break;
                case 1: FSettings.MP3_CRC = !FSettings.MP3_CRC; break;
                case 2: FSettings.MP3_Private = !FSettings.MP3_Private; break;
                default: FSettings.MP3_Original = !FSettings.MP3_Original; break;
            }
            CreateMenu(FList.ContextMenuStrip.Items);
        }
        /// <summary>Event: KeyDown</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_KeyDown(object pSender, System.Windows.Forms.KeyEventArgs e)
        {
            if (e.KeyCode == System.Windows.Forms.Keys.Escape) Close();
        }
    }
}
